package com.example.demo.aspect;

import com.example.demo.anno.AutoCustomAnnotation;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/*
 *
 *   @Author:Sjy
 *   @Date: 2024/4/8-04-08-19:41
 *   通过AOP完成对自定义注解下的方法进行自动化缓存
 */

@Slf4j //日志注解
@Aspect //标记是一个aop切面
@Component //放到IOC容器
public class RedisCachingAspect {

    @Autowired
    private RedisTemplate redisTemplate;


    @Around("@annotation(com.example.demo.anno.AutoCustomAnnotation)")//可以写全路径
    public Object cacheAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //------------------------------获取注解的参数开始-----------------------------------------
        //获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取方法对象
        Method method = signature.getMethod();
        //通过方法对象，获取方法上携带的注解
        AutoCustomAnnotation annotation = method.getAnnotation(AutoCustomAnnotation.class);
        //获取自定义注解的参数
        long ttl = annotation.ttl();
        String group = annotation.group();

        //------------------------------获取注解的参数结束------------------------------------------
        //------------------------------通过现有条件拼接一个唯一key 开始-----------------------------------------
        String key = getCacheKey(group,signature,joinPoint);
        log.info("key{}",key);
        //------------------------------通过现有条件拼接一个唯一key 结束------------------------------------------

        //------------------------------判断redis是否有这个key 开始-----------------------------------------
        if(redisTemplate.hasKey(key)){
            log.info("查询缓存逻辑");
            //把json字符串转换成对应的对象
            Gson gson = new Gson();
            Object o = gson.fromJson(redisTemplate.opsForValue().get(key).toString(),method.getReturnType());
            return o;
        }
        //------------------------------判断redis是否有这个key 结束-----------------------------------------

        //proceed原方法的返回值
        Object result = joinPoint.proceed();
        //----------------------------------在redis里面保存一个------------------------------------
        if(ttl > 0){
            redisTemplate.opsForValue().set(key,result,ttl, TimeUnit.MILLISECONDS);
        }else{
            redisTemplate.opsForValue().set(key,result);
        }
        log.info("数据库逻辑");
        return result;
    }

    //用来生成一个key
    public String getCacheKey(String group,MethodSignature methodSignature, JoinPoint joinPoint){
        //分组拼接上参数
        //注解分组 + 方法名 + 参数
        String key = group + methodSignature.getName() + ":" + Arrays.toString(joinPoint.getArgs());
        return key;
    }


}
